home *** CD-ROM | disk | FTP | other *** search
/ Sprite 1984 - 1993 / Sprite 1984 - 1993.iso / src / daemons / ipServer / RCS / tcpTimer.c,v < prev    next >
Encoding:
Text File  |  1992-08-19  |  14.5 KB  |  635 lines

  1. head     1.6;
  2. branch   ;
  3. access   ;
  4. symbols  ;
  5. locks    ; strict;
  6. comment  @ * @;
  7.  
  8.  
  9. 1.6
  10. date     89.07.23.17.35.18;  author nelson;  state Exp;
  11. branches ;
  12. next     1.5;
  13.  
  14. 1.5
  15. date     89.03.23.09.56.49;  author brent;  state Exp;
  16. branches ;
  17. next     1.4;
  18.  
  19. 1.4
  20. date     88.09.28.11.49.10;  author mendel;  state Exp;
  21. branches ;
  22. next     1.3;
  23.  
  24. 1.3
  25. date     88.08.16.11.20.27;  author mendel;  state Exp;
  26. branches ;
  27. next     1.2;
  28.  
  29. 1.2
  30. date     88.04.27.09.10.43;  author brent;  state Exp;
  31. branches ;
  32. next     1.1;
  33.  
  34. 1.1
  35. date     88.04.27.08.52.32;  author brent;  state Exp;
  36. branches ;
  37. next     ;
  38.  
  39.  
  40. desc
  41. @TCP Timer routines
  42. @
  43.  
  44.  
  45. 1.6
  46. log
  47. @Fixed up debugging info.
  48. @
  49. text
  50. @/* 
  51.  * tcpTimer.c --
  52.  *
  53.  *    The file contains routines to manage the 4 TCP connection timers.
  54.  *    The timers are described in detail in tcpTimer.h.
  55.  *
  56.  *    Based on 4.3BSD    @@(#)tcp_timer.c    7.12 (Berkeley) 3/16/88
  57.  *
  58.  * Copyright 1987 Regents of the University of California
  59.  * All rights reserved.
  60.  * Permission to use, copy, modify, and distribute this
  61.  * software and its documentation for any purpose and without
  62.  * fee is hereby granted, provided that the above copyright
  63.  * notice appear in all copies.  The University of California
  64.  * makes no representations about the suitability of this
  65.  * software for any purpose.  It is provided "as is" without
  66.  * express or implied warranty.
  67.  */
  68.  
  69. #ifndef lint
  70. static char rcsid[] = "$Header: tcpTimer.c,v 1.2 89/06/08 20:18:43 mnelson Exp $ SPRITE (Berkeley)";
  71. #endif not lint
  72.  
  73.  
  74. #include "sprite.h"
  75. #include "ipServer.h"
  76. #include "stat.h"
  77. #include "socket.h"
  78. #include "tcp.h"
  79. #include "tcpInt.h"
  80.  
  81. #include "time.h"
  82.  
  83. /*
  84.  * Number of times per second that TimeoutHandler is called. 
  85.  */
  86. #ifdef SPUR
  87. #define TIMEOUTS_PER_SEC    1
  88. #else
  89. #define TIMEOUTS_PER_SEC    4
  90. #endif
  91.  
  92. int tcpKeepLen = 1;    /* must be nonzero for 4.2 compat- XXX */
  93. int tcpKeepIdle = TCP_KEEP_TIME_IDLE;
  94. int tcpKeepIntvl = TCP_KEEP_TIME_INTVL;
  95. int tcpMaxIdle;
  96.  
  97. static int backoff[TCP_MAX_RXT_SHIFT+1] = {
  98.     1, 2, 4, 8, 16, 32, 64, 64, 64, 64, 64, 64, 64
  99. };
  100.  
  101. /*
  102.  * Forward declarations.
  103.  */
  104. static void    TimeoutHandler();
  105. static Boolean    ProcessTimers();
  106.  
  107.  
  108.  
  109. /*
  110.  *----------------------------------------------------------------------
  111.  *
  112.  * TCPTimerInit --
  113.  *
  114.  *    Sets up the TCP timeout handler so it is called at regular
  115.  *    intervals.
  116.  *
  117.  * Results:
  118.  *    None.
  119.  *
  120.  * Side effects:
  121.  *    A handler will be called at regular intervals.
  122.  *
  123.  *----------------------------------------------------------------------
  124.  */
  125.  
  126. void
  127. TCPTimerInit()
  128. {
  129.     Time interval;
  130.     Time_Divide(time_OneSecond, TIMEOUTS_PER_SEC, &interval);
  131.     (void)Fs_TimeoutHandlerCreate(interval,TRUE, TimeoutHandler, (ClientData)0);
  132. }
  133.  
  134. /*
  135.  *----------------------------------------------------------------------
  136.  *
  137.  * TimeoutHandler --
  138.  *
  139.  *    This routine handles 2 types of timeouts:
  140.  *     1) the fast timeout is needed for sending delayed ACKs, and
  141.  *     2) the slow timeout updates the timers in all active TCB's and
  142.  *        causes finite state machine actions if the timers expire.
  143.  *
  144.  * Results:
  145.  *    None.
  146.  *
  147.  * Side effects:
  148.  *    ACKs may be sent, timers are updated.
  149.  *
  150.  *----------------------------------------------------------------------
  151.  */
  152.  
  153. /*ARGSUSED*/
  154. static void
  155. TimeoutHandler(data, time)
  156.     ClientData    data;        /* Ignored. */
  157.     Time    time;        /* Ignored. */
  158. {
  159.     register TCPControlBlock *tcbPtr;
  160.     Sock_InfoPtr    sockPtr;
  161.     register int     i;
  162.     Boolean        processTimers;
  163.     static int         count = 0;
  164.  
  165.     stats.tcp.timerCalls++;
  166.  
  167.     /*
  168.      * The timers are processed once every second.
  169.      */
  170.     count++;
  171.     if (count == TIMEOUTS_PER_SEC/TIMER_UPDATE_RATE ||
  172.         (TIMEOUTS_PER_SEC/TIMER_UPDATE_RATE == 0)) {
  173.     count = 0;
  174.     processTimers = TRUE;
  175.     } else {
  176.     processTimers = FALSE;
  177.     }
  178.  
  179.     /*
  180.      * Go through all active TCP sockets and see if ACKs need to be
  181.      * sent and if the timers should be updated.
  182.      */
  183.     sockPtr = (Sock_InfoPtr) NULL;
  184.     while (TRUE) {
  185.     sockPtr = Sock_ScanList(TCP_PROTO_INDEX, sockPtr);
  186.     if (sockPtr == (Sock_InfoPtr) NULL) {
  187.         break;
  188.     }
  189.     tcbPtr = TCPSockToTCB(sockPtr);
  190.  
  191.     if (tcbPtr == (TCPControlBlock *) NULL) {
  192.         continue;
  193.     }
  194.  
  195.     /*
  196.      * At every timeout, process send an ACK if it was delayed.
  197.      */
  198.     if (tcbPtr->flags & TCP_DELAY_ACK) {
  199.  
  200.         tcbPtr->flags &= ~TCP_DELAY_ACK;
  201.         tcbPtr->flags |= TCP_ACK_NOW;
  202.         stats.tcp.delayAck++;
  203.         if (ips_Debug) {
  204.         fprintf(stderr, "TCP Timer: delay ack output\n");
  205.         }
  206.  
  207.         (void) TCPOutput(sockPtr, tcbPtr);
  208.     }
  209.  
  210.     if (processTimers) {
  211.  
  212.         /*
  213.          *  Update active timers.
  214.          */
  215.  
  216.         for (i = 0; i < TCP_NUM_TIMERS; i++) {
  217.         if (tcbPtr->timer[i] != 0) {
  218.             tcbPtr->timer[i]--;
  219.             if (tcbPtr->timer[i] == 0) {
  220.             if (!ProcessTimers(sockPtr, tcbPtr, i)) {
  221.                 goto tcbGone;
  222.             }
  223.             }
  224.         }
  225.         }
  226.         tcbPtr->idle++;
  227.         if (tcbPtr->rtt) {
  228.         tcbPtr->rtt++;
  229.         }
  230. tcbGone:
  231.         tcpISS += TCP_INIT_SEND_SEQ_INCR;
  232.     }
  233.     }
  234. }
  235.  
  236.  
  237.  
  238. /*
  239.  *----------------------------------------------------------------------
  240.  *
  241.  * ProcessTimers --
  242.  *
  243.  *    This routine is called once a second to update the 4 TCP
  244.  *    timers. The type of action taken depends on the timer. 
  245.  *
  246.  * Results:
  247.  *    TRUE    - the connection is still open and the tcb is valid.
  248.  *    FALSE    - the connection has been closed and the tcb is no longer
  249.  *          valid.
  250.  *
  251.  * Side effects:
  252.  *    The timer is updated. A connection may be dropped.
  253.  *
  254.  *----------------------------------------------------------------------
  255.  */
  256.  
  257. static Boolean
  258. ProcessTimers(sockPtr, tcbPtr, timer)
  259.     Sock_InfoPtr        sockPtr;    /* TCP socket. */
  260.     register TCPControlBlock    *tcbPtr;    /* TCB for the socket. */
  261.     int             timer;        /* Which timer. */
  262. {
  263.     register int rexmt;
  264.  
  265.     switch (timer) {
  266.  
  267.     /*
  268.      * 2 MSL timeout in shutdown went off.  If we're closed but
  269.      * still waiting for peer to close and connection has been idle
  270.      * too long, or if 2MSL time is up from TIME_WAIT, delete connection
  271.      * control block.  Otherwise, check again in a bit.
  272.      */
  273.     case TCP_TIMER_2MSL:
  274.         stats.tcp.mslTimeout++;
  275.         if (tcbPtr->state != TIME_WAIT &&
  276.         tcbPtr->idle <= tcpMaxIdle) {
  277.         tcbPtr->timer[TCP_TIMER_2MSL] = TCP_KEEP_TIME_INTVL;
  278.         } else {
  279.         TCPCloseConnection(sockPtr, tcbPtr);
  280.         return(FALSE);
  281.         }
  282.         break;
  283.  
  284.  
  285.     /*
  286.      * The retransmission timer went off.  Our message has not
  287.      * been ACKed within the retransmit interval.  Back off
  288.      * to a longer retransmit interval and retransmit one segment.
  289.      */
  290.     case TCP_TIMER_REXMT:
  291.         tcbPtr->rxtshift++;
  292.         if (tcbPtr->rxtshift > TCP_MAX_RXT_SHIFT) {
  293.             tcbPtr->rxtshift = TCP_MAX_RXT_SHIFT;
  294.         stats.tcp.timeoutDrop++;
  295.         TCPDropConnection(sockPtr, tcbPtr, GEN_TIMEOUT);
  296.         return(FALSE);
  297.         }
  298.         stats.tcp.rexmtTimeout++;
  299.         rexmt = ((tcbPtr->srtt >> 2) + tcbPtr->rttvar) >> 1;
  300.         rexmt *= backoff[tcbPtr->rxtshift];
  301.         TCP_TIMER_RANGESET(tcbPtr->rxtcur,
  302.             rexmt, TCP_MIN_REXMT_TIME, TCP_MAX_REXMT_TIME);
  303.         tcbPtr->timer[TCP_TIMER_REXMT] = tcbPtr->rxtcur;
  304.         /*
  305.          * If losing, let the lower level know and try for
  306.          * a better route.  Also, if we backed off this far,
  307.          * our smooth rtt estimate is probably bogus.  Clobber it
  308.          * so we'll take the next rtt measurement as our smooth rtt;
  309.          * move the current smooth rtt into rttvar to keep the current
  310.          * retransmit times until then.
  311.          */
  312.         if (tcbPtr->rxtshift > TCP_MAX_RXT_SHIFT / 4) {
  313.         Sock_BadRoute(sockPtr);
  314.         tcbPtr->rttvar += (tcbPtr->srtt >> 2);
  315.         tcbPtr->srtt = 0;
  316.         }
  317.         tcbPtr->send.next = tcbPtr->send.unAck;
  318.  
  319.         /*
  320.          * If timing a segment in this window, and we have already 
  321.          * gotten some timing estimate, stop the timer.
  322.          */
  323.         tcbPtr->rtt = 0;
  324.  
  325.         /*
  326.          * Close the congestion window down to one segment
  327.          * (we'll open it by one segment for each ack we get).
  328.          * Since we probably have a window's worth of unacked
  329.          * data accumulated, this "slow start" keeps us from
  330.          * dumping all that data as back-to-back packets (which
  331.          * might overwhelm an intermediate gateway).
  332.          *
  333.          * There are two phases to the opening: Initially we
  334.          * open by one mss on each ack.  This makes the window
  335.          * size increase exponentially with time.  If the
  336.          * window is larger than the path can handle, this
  337.          * exponential growth results in dropped packet(s)
  338.          * almost immediately.  To get more time between 
  339.          * drops but still "push" the network to take advantage
  340.          * of improving conditions, we switch from exponential
  341.          * to linear window opening at some threshhold size.
  342.          * For a threshhold, we use half the current window
  343.          * size, truncated to a multiple of the mss.
  344.          *
  345.          * (the minimum cwnd that will give us exponential
  346.          * growth is 2 mss.  We don't allow the threshhold
  347.          * to go below this.)
  348.          */
  349.         {
  350.         unsigned int win; 
  351.         win = MIN(tcbPtr->send.window, tcbPtr->send.congWindow) / 2 / 
  352.                 tcbPtr->maxSegSize;
  353.         if (win < 2) {
  354.             win = 2;
  355.         }
  356.         tcbPtr->send.congWindow = tcbPtr->maxSegSize;
  357.         tcbPtr->send.cwSizeThresh = win * tcbPtr->maxSegSize;
  358.         }
  359.         if (ips_Debug) {
  360.         fprintf(stderr, "TCP Timer: rexmt output\n");
  361.         }
  362.         (void) TCPOutput(sockPtr, tcbPtr);
  363.         break;
  364.  
  365.  
  366.     /*
  367.      * The persist timer has expired: see of the window is still closed.
  368.      * Force a byte to be output, if possible.
  369.      */
  370.     case TCP_TIMER_PERSIST:
  371.         stats.tcp.persistTimeout++;
  372.         TCPSetPersist(tcbPtr);
  373.         tcbPtr->force = 1;
  374.         if (ips_Debug) {
  375.         fprintf(stderr, "TCP Timer: persist output\n");
  376.         }
  377.         (void) TCPOutput(sockPtr, tcbPtr);
  378.         tcbPtr->force = 0;
  379.         break;
  380.  
  381.     /*
  382.      * Keep-alive timer went off: send something or drop the 
  383.      * connection if it has been idle for too long.
  384.      */
  385.     case TCP_TIMER_KEEP_ALIVE:
  386.         stats.tcp.keepTimeout++;
  387.         if (TCP_UNSYNCHRONIZED(tcbPtr->state)) {
  388.         stats.tcp.keepDrops++;
  389.         TCPDropConnection(sockPtr, tcbPtr, GEN_TIMEOUT);
  390.         return(FALSE);
  391.         }
  392.         if (Sock_IsOptionSet(sockPtr, NET_OPT_KEEP_ALIVE) &&
  393.         (tcbPtr->state == ESTABLISHED || tcbPtr->state == CLOSE_WAIT)) {
  394.  
  395.         if (tcbPtr->idle >= tcpKeepIdle + tcpMaxIdle) {
  396.                 stats.tcp.keepDrops++;
  397.             TCPDropConnection(sockPtr, tcbPtr, GEN_TIMEOUT);
  398.             return(FALSE);
  399.         }
  400.         /*
  401.          * Send a packet designed to force a response if the peer
  402.          * is up and reachable:  either an ACK if the connection
  403.          * is still alive, or an RESET if the peer has closed the
  404.          * connection due to timeout or reboot.  Using sequence
  405.          * number tcbPtr->send.unAck-1 causes the transmitted
  406.          * zero-length segment to lie outside the receive window;
  407.          * by the protocol spec, this requires the correspondent
  408.          * TCP to respond.
  409.          */
  410.         stats.tcp.keepProbe++;
  411.         TCPRespond(sockPtr, tcbPtr->templatePtr, 
  412.             tcbPtr->IPTemplatePtr, tcbPtr->recv.next - tcpKeepLen, 
  413.             tcbPtr->send.unAck - 1, 0);
  414.         tcbPtr->timer[TCP_TIMER_KEEP_ALIVE] = tcpKeepIntvl;
  415.         } else {
  416.         tcbPtr->timer[TCP_TIMER_KEEP_ALIVE] = tcpKeepIdle;
  417.         }
  418.         break;
  419.  
  420.     }
  421.     return(TRUE);
  422. }
  423.  
  424.  
  425. /*
  426.  *----------------------------------------------------------------------
  427.  *
  428.  * TCPSetPersist --
  429.  *
  430.  *    Starts or restarts the persistance timer.
  431.  *
  432.  * Results:
  433.  *    None.
  434.  *
  435.  * Side effects:
  436.  *    The timer is updated.
  437.  *
  438.  *----------------------------------------------------------------------
  439.  */
  440.  
  441. void
  442. TCPSetPersist(tcbPtr)
  443.     register TCPControlBlock *tcbPtr;
  444. {
  445.     register int t = ((tcbPtr->srtt >> 2) + tcbPtr->rttvar) >> 1;
  446.  
  447.     if (tcbPtr->timer[TCP_TIMER_REXMT] != 0) {
  448.      panic("TCPSetPersist REXMT timer != 0 (%d)\n",
  449.         tcbPtr->timer[TCP_TIMER_REXMT]);
  450.     }
  451.  
  452.     TCP_TIMER_RANGESET(tcbPtr->timer[TCP_TIMER_PERSIST],
  453.     t * backoff[tcbPtr->rxtshift],
  454.     TCP_MIN_PERSIST_TIME, TCP_MAX_PERSIST_TIME);
  455.  
  456.     if (tcbPtr->rxtshift < TCP_MAX_RXT_SHIFT) {
  457.     tcbPtr->rxtshift++;
  458.     }
  459. }
  460.  
  461.  
  462. /*
  463.  *----------------------------------------------------------------------
  464.  *
  465.  * TCPCancelTimers --
  466.  *
  467.  *    Cancel all timers for a TCP control block.
  468.  *
  469.  * Results:
  470.  *    None.
  471.  *
  472.  * Side effects:
  473.  *    The timers are cancelled.
  474.  *
  475.  *----------------------------------------------------------------------
  476.  */
  477.  
  478. void
  479. TCPCancelTimers(tcbPtr)
  480.     register TCPControlBlock *tcbPtr;
  481. {
  482.     register int i;
  483.  
  484.     for (i = 0; i < TCP_NUM_TIMERS; i++) {
  485.     tcbPtr->timer[i] = 0;
  486.     }
  487. }
  488. @
  489.  
  490.  
  491. 1.5
  492. log
  493. @Removed stdio.h include
  494. @
  495. text
  496. @d21 1
  497. a21 1
  498. static char rcsid[] = "$Header: /sprite/src/daemons/ipServer/RCS/tcpTimer.c,v 1.4 88/09/28 11:49:10 mendel Exp Locker: brent $ SPRITE (Berkeley)";
  499. d154 4
  500. d310 3
  501. d325 3
  502. @
  503.  
  504.  
  505. 1.4
  506. log
  507. @Bug fixes and a patch for SPUR.
  508. @
  509. text
  510. @d21 1
  511. a21 1
  512. static char rcsid[] = "$Header: tcpTimer.c,v 1.3 88/08/16 11:20:27 mendel Exp $ SPRITE (Berkeley)";
  513. a32 1
  514. #include <stdio.h>
  515. @
  516.  
  517.  
  518. 1.3
  519. log
  520. @Converted to use new libc.a
  521. @
  522. text
  523. @d21 1
  524. a21 1
  525. static char rcsid[] = "$Header: tcpTimer.c,v 1.2 88/04/27 09:10:43 brent Exp $ SPRITE (Berkeley)";
  526. d38 5
  527. a42 1
  528. #define TIMEOUTS_PER_SEC    5
  529. d123 2
  530. a124 1
  531.     if (count == TIMEOUTS_PER_SEC) {
  532. a245 1
  533.  
  534. a251 1
  535.  
  536. d260 1
  537. a260 1
  538.         if (tcbPtr->rxtshift >= TCP_MAX_RXT_SHIFT / 4) {
  539. @
  540.  
  541.  
  542. 1.2
  543. log
  544. @New update with Jacobson enhancements
  545. @
  546. text
  547. @d21 1
  548. a21 1
  549. static char rcsid[] = "$Header: tcpTimer.c,v 6.1 88/04/24 23:15:05 andrew Exp $ SPRITE (Berkeley)";
  550. a31 2
  551. #include "sys.h"
  552. #include "fs.h"
  553. d33 1
  554. d387 1
  555. a387 1
  556.     Sys_Panic(SYS_FATAL, "TCPSetPersist REXMT timer != 0 (%d)\n",
  557. @
  558.  
  559.  
  560. 1.1
  561. log
  562. @Initial revision
  563. @
  564. text
  565. @d7 1
  566. a7 1
  567.  *    Based on 4.3BSD    @@(#)tcp_timer.c    7.5 (Berkeley) 6/6/87
  568. a8 1
  569.  *
  570. d21 1
  571. a21 1
  572. static char rcsid[] = "$Header: tcpTimer.c,v 6.0 87/09/08 15:57:24 andrew Stable $ SPRITE (Berkeley)";
  573. d42 3
  574. d47 1
  575. a47 1
  576.     1, 2, 4, 6, 8, 10, 15, 20, 30, 30, 30, 30, 30
  577. d171 2
  578. a172 2
  579.         if (tcbPtr->roundTripTime) {
  580.         tcbPtr->roundTripTime++;
  581. d220 2
  582. a221 3
  583.         tcbPtr->idle <= TCP_MAX_IDLE_TIME) {
  584.  
  585.         tcbPtr->timer[TCP_TIMER_2MSL] = TCP_KEEP_TIME;
  586. d235 3
  587. a237 2
  588.         tcbPtr->retransShift++;
  589.         if (tcbPtr->retransShift > TCP_MAX_RXT_SHIFT) {
  590. d244 3
  591. a246 7
  592.         if (tcbPtr->smoothRTT == 0) {
  593.         rexmt = tcpSmoothBeta * TCP_SRTT_DEFLT_TIME;
  594.         } else {
  595.         rexmt = (int)(tcpSmoothBeta * tcbPtr->smoothRTT);
  596.         }
  597.         rexmt *= backoff[tcbPtr->retransShift - 1];
  598.         TCP_TIMER_RANGESET(tcbPtr->timer[TCP_TIMER_REXMT], 
  599. d248 1
  600. d251 6
  601. a256 2
  602.          * If losing, let the lower level know
  603.          * and try for a better route.
  604. d258 4
  605. a261 3
  606.         if ((tcbPtr->retransShift >= TCP_MAX_RXT_SHIFT / 4) ||
  607.         (rexmt >= 10)) {
  608.             Sock_BadRoute(sockPtr);
  609. d269 1
  610. a269 3
  611.         if ((tcbPtr->roundTripTime != 0) && (tcbPtr->smoothRTT != 0)) {
  612.         tcbPtr->roundTripTime = 0;
  613.         }
  614. d278 16
  615. d295 10
  616. a304 1
  617.         tcbPtr->send.congWindow = tcbPtr->maxSegSize;
  618. d335 1
  619. a335 1
  620.         if (tcbPtr->idle >= TCP_MAX_IDLE_TIME) {
  621. d354 3
  622. a357 1
  623.         tcbPtr->timer[TCP_TIMER_KEEP_ALIVE] = TCP_KEEP_TIME;
  624. d385 1
  625. d393 2
  626. a394 2
  627.     ((int)(tcpSmoothBeta * tcbPtr->smoothRTT)) << tcbPtr->retransShift,
  628.     TCP_MIN_PERSIST_TIME, TCP_MAX_REXMT_TIME);
  629. d396 2
  630. a397 3
  631.     tcbPtr->retransShift++;
  632.     if (tcbPtr->retransShift >= TCP_MAX_RXT_SHIFT) {
  633.     tcbPtr->retransShift = 0;
  634. @
  635.